

import 'dart:async';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:logger/logger.dart' show Level;

enum YKRecordFileType {
  mp3,
}

class YKRecordConfig {

  Future<bool> Function()? checkAutCallBack;

  static YKRecordConfig? _instance;

  static YKRecordConfig get instance {
    _instance ??= YKRecordConfig._();
    return _instance!;
  }

  YKRecordConfig._();

  bool _isRecording = false;

  bool get isRecording => _isRecording;

  StreamController<bool> _stateStreamController = StreamController<bool>.broadcast();

  Stream<bool> get stateStream => _stateStreamController.stream;

  void _setRecording(bool isRecording) {
    bool currentRecod = _isRecording;
    _isRecording = isRecording;

    if (currentRecod != isRecording) {
      _stateStreamController.add(_isRecording);
    }
  }

}

class YKRecordDelegate {

  void Function(bool isRecording)? statusChangeCallBack;

  void Function(String msg)? logCallBack;

  void Function(String error)? errorCallBack;

  void Function(int seconds)? progressCallBack;

  void Function(double decibels)? decibelsCallBack;

  YKRecordDelegate({this.statusChangeCallBack, this.logCallBack, this.errorCallBack, this.progressCallBack, this.decibelsCallBack});

}

class YKRecordController {

  Future<bool> Function()? _checkAutCallBack;

  YKRecord? _record;

  Future<void> start(String path, {int maxSeconds = 0, YKRecordFileType type = YKRecordFileType.mp3}) async {

    _record?._start(path, maxSeconds: maxSeconds, type: type);

    return;
  }

  Future<void> end() async {

    final path = _record?._end();

    return path;
  }

  YKRecordController({Future<bool> Function()? checkAutCallBack}) {
    _checkAutCallBack = checkAutCallBack;
  }

}

class YKRecord {

  final void Function(String? path) finishCallBack;

  YKRecordDelegate? delegate;

  YKRecordController? _controller;

  YKRecord({required this.finishCallBack, YKRecordController? controller, this.delegate}) {
    _controller = controller;
    _controller?._record = this;
  }

  bool _isRecording = false;

  String? _currentPath;

  FlutterSoundRecorder? _recorder;
  StreamSubscription<RecordingDisposition>? _recorderSubscription;

  void _start(String path, {int maxSeconds = 0, YKRecordFileType type = YKRecordFileType.mp3}) async {

    if (_isRecording) {
      delegate?.errorCallBack?.call("录音中，不能操作");
      return;
    }

    if (YKRecordConfig.instance.checkAutCallBack != null) {
      final result = await YKRecordConfig.instance.checkAutCallBack!.call();
      if (!result) {
        delegate?.errorCallBack?.call("未获取权限");
        return;
      }
    } else if (_controller != null && _controller!._checkAutCallBack != null) {
      final result = await _controller!._checkAutCallBack!.call();
      if (!result) {
        delegate?.errorCallBack?.call("未获取权限");
        return;
      }
    } else {
      //未获取权限
      delegate?.errorCallBack?.call("未获取权限");
      return;
    }

    try {
      _recorder = await FlutterSoundRecorder(logLevel: Level.error).openRecorder();

      await _recorder?.setSubscriptionDuration(const Duration(seconds: 1));
      _recorderSubscription = _recorder?.onProgress?.listen((event) {
        delegate?.progressCallBack?.call(event.duration.inSeconds);
        delegate?.decibelsCallBack?.call(event.decibels ?? 0);
      });


      //录音逻辑
      await _recorder?.startRecorder(toFile: path);
      _isRecording = _recorder?.isRecording ?? false;
      YKRecordConfig.instance._setRecording(_isRecording);
      delegate?.statusChangeCallBack?.call(_isRecording);


      _currentPath = path;
    } catch (e) {
      delegate?.errorCallBack?.call(e.toString());
    }
  }

  Future<void> _end() async {

    if (!_isRecording) {
      delegate?.errorCallBack?.call("未在录音中");
      return;
    }

    //结束录音逻辑
    try {
      final result = await _recorder?.stopRecorder();
      if (_recorderSubscription != null) {
        _recorderSubscription?.cancel();
        _recorderSubscription = null;
      }

      bool isRecording = _recorder?.isRecording ?? false;

      await _recorder?.closeRecorder();
      _recorder = null;

      _isRecording = isRecording;
      YKRecordConfig.instance._setRecording(_isRecording);
      delegate?.statusChangeCallBack?.call(_isRecording);

      finishCallBack.call(result);
    } catch (e) {
      delegate?.errorCallBack?.call(e.toString());
      return null;
    }
  }
}